<?php

namespace app\hooks;

use app\api\model\ModeOrders;
use app\api\model\ModeOrdersLog;
use app\api\model\ModeThreeLevel;
use app\api\model\User;
use think\facade\Db;
use think\facade\Log;
use think\helper\Str;

class ModeThreeHook
{

    public const RATE_OF_DIRECT = 10;

    public const RATE_OF_STATIC = 8;
    public const RATE_OF_PARTNER = 10;
    public const RATE_OF_PARTNER_PINGJI = 10;
    public const RATE_OF_BALANCE = 80;
    public const RATE_OF_FEE = 0;
    public const RATE_OF_INTEGRAL = 20;

    public static function paid_run($order_id)
    {
        if ($order_info = ModeOrders::where('id', $order_id)->where('type', 4)->findOrEmpty()->toArray()) {

            $user_info = User::findOrEmpty((int)$order_info['user_id'])->toArray();

            $achievements = ['direct' => [], 'jicha' => [], 'pingji' => [], 'partner' => [], 'partner_pingji' => []];

            if ($parent_users = ModeHook::getUserParents((int)$user_info['pid'])) {

                $direct_parent_user = $parent_users[0];

                $achievements['direct'][$direct_parent_user['id']] = ModeHook::computePercentAmount($order_info['principal'], self::RATE_OF_DIRECT);

//                $achievements = self::computeLevelAmounts($user_info['mode_three_level_id'], $parent_users, $order_info['principal'], $achievements);

                $achievements = self::computePartnerAmounts($parent_users, $order_info['principal'], $achievements);
            }

            $order_info = array_merge($order_info, ['active_achievements' => $achievements]);

            ModeOrders::where('id', $order_info['id'])->update(['active_achievements' => json_encode($achievements)]);

            self::release($order_info, $achievements);
        }
        return true;
    }

    public static function static_run()
    {
        ModeOrders::where('is_delete', 0)->where('type', 4)->where('status', 'payed')->whereNotNull('pay_time')->update(['achievements' => '', 'last_achievements_time' => 0]);

        if ($orders = ModeOrders::where('is_delete', 0)->where('type', 4)->where('status', 'payed')->whereNotNull('pay_time')->where('remain_earnings', '>', 0)->order('pay_time', 'asc')->select()) {

            foreach ($orders as $ok => $order) {

                $order = $order->toArray();

                $user_info = User::findOrEmpty((int)$order['user_id'])->toArray();

                $achievements = ['static' => ModeHook::computePercentAmount($order['principal'], self::RATE_OF_STATIC, 1000), 'jicha' => [], 'pingji' => []];

                if ($parent_users = ModeHook::getUserParents((int)$user_info['pid'])) {

//                    $direct_parent_user = $parent_users[0];
//
//                    $achievements['direct'][$direct_parent_user['id']] = ModeHook::computePercentAmount($achievements['static'], self::RATE_OF_DIRECT);

                    //2024-04-28 易辰确认需要将模式三更改为和模式一一样的级差分配机制，当前这行为旧分配方法
//                    $achievements = self::computeLevelAmounts($user_info['mode_three_level_id'], $parent_users, $achievements['static'], $achievements);

                    //2024-04-28 易辰确认需要将模式三更改为和模式一一样的级差分配机制，当前这行为新分配方法
                    $achievements = self::computeParentsAmounts($user_info['mode_three_level_id'], $parent_users, $achievements['static'], $achievements);
                }

                $orders[$ok] = $order = array_merge($order, compact('achievements'));

                ModeOrders::where('id', $order['id'])->update(['achievements' => json_encode($achievements), 'last_achievements_time' => time()]);

                $release = self::release($order, $achievements);

                unset($orders[$ok], $achievements, $release);
            }
        }
        return true;
    }

    private static function computePartnerAmounts($parent_users, $amount, $achievements)
    {

        $partner_amount = $partner_pingji_amount = ModeHook::computePercentAmount($amount, self::RATE_OF_PARTNER);
        $partner_complete = false;

        foreach ($parent_users as $pk => $parent_user) {

            if ((int)$parent_user['invest_count'] > 0) {

                if (!$partner_complete) {

                    $achievements['partner'][$parent_user['id']] = $partner_amount;
                    $partner_complete = true;

                } else {

                    $partner_pingji_amount = ModeHook::computePercentAmount($partner_pingji_amount, self::RATE_OF_PARTNER_PINGJI);

                    if ($partner_pingji_amount >= 1000) {

                        $achievements['partner_pingji'][$parent_user['id']] =  $partner_pingji_amount;

                    } else {

                        break;

                    }
                }
            }

        }

        return $achievements;
    }

    private static function computeParentsAmounts($user_level_id, $parent_users, $amount, $achievements)
    {
        $levels = ModeThreeLevel::field(implode(', ', ['id', 'name', 'rate', 'equality_rate']))->order('id', 'asc')->select()->toArray();

        $levels = array_column($levels, null, 'id');
        $levels[0] = ['id' => 0, 'name' => '游客', 'rate' => 0, 'equality_rate' => 0];
        sort($levels);

        $current_user_level_id = (int)$user_level_id;
        $current_user_level_rate = (float)$levels[$current_user_level_id]['rate'];

        //获取级差金额
        $jicha_amounts = [];

        foreach ($parent_users as $pk => $parent_user) {

            if ((int)$parent_user['mode_three_level_id'] > $current_user_level_id) {

                $rate = (float)$levels[(int)$parent_user['mode_three_level_id']]['rate'] - $current_user_level_rate;

                $jicha_amounts[(int)$parent_user['mode_three_level_id']] = $jicha_amount = ModeHook::computePercentAmount($amount, $rate);

                $achievements['jicha'][(int)$parent_user['mode_three_level_id']][(int)$parent_user['id']] = $jicha_amount;

                $current_user_level_rate = (float)$levels[($current_user_level_id = (int)$parent_user['mode_three_level_id'])]['rate'];

            }
        }

        foreach ($levels as $level) {

            if ($level['id'] <= (int)$user_level_id || !isset($achievements['jicha'][(int)$level['id']])) {

                continue;

            }

            //获取级差分配金额
            $pingji_amount = (int)$jicha_amounts[(int)$level['id']];

            foreach ($parent_users as $pk => $parent_user) {

                //判断等级是否足够
                if ((int)$parent_user['mode_three_level_id'] === (int)$level['id'] && !isset($achievements['jicha'][(int)$level['id']][(int)$parent_user['id']])) {

                    $pingji_amount = ModeHook::computePercentAmount($pingji_amount, (float)$level['equality_rate']);

                    if ($pingji_amount >= 100) {

                        $achievements['pingji'][(int)$level['id']][(int)$parent_user['id']] = $pingji_amount;

                    } else {

                        break;

                    }
                }

            }

        }

        return $achievements;
    }

    private static function computeLevelAmounts($user_level_id, $parent_users, $amount, $achievements)
    {

        $levels = ModeThreeLevel::field(implode(', ', ['id', 'name', 'rate', 'equality_rate']))->order('id', 'asc')->select()->toArray();

        $levels = array_column($levels, null, 'id');
        $levels[0] = ['id' => 0, 'name' => '游客', 'rate' => 0, 'equality_rate' => 0];
        sort($levels);

        $current_user_level_rate = (float)$levels[(int)$user_level_id]['rate'];

        foreach ($levels as $level) {

            if ($level['id'] <= (int)$user_level_id) {
                continue;
            }

            $rate = (float)$level['rate'] - $current_user_level_rate;

            if ($rate <= 0) {
                continue;
            }

            $jicha_amount = $pingji_amount = ModeHook::computePercentAmount($amount, $rate);
            $jicha_complete = false;


            foreach ($parent_users as $pk => $parent_user) {

                if ((int)$parent_user['mode_three_level_id'] === $level['id']) {

                    if (!$jicha_complete) {

                        $achievements['jicha'][$level['id']][$parent_user['id']] = $jicha_amount;
                        $jicha_complete = true;

                    } else {

                        $pingji_amount = ModeHook::computePercentAmount($pingji_amount, (float)$level['equality_rate']);

                        if ($pingji_amount >= 100) {

                            $achievements['pingji'][$level['id']][$parent_user['id']] = $pingji_amount;

                        } else {

                            break;

                        }
                    }
                }
            }

            if ($jicha_complete) {

                $current_user_level_rate = (float)$level['rate'];

            }

            unset($jicha_amount, $jicha_complete);
        }

        return $achievements;
    }

    private static function release($order_info, $achievements)
    {
        foreach ($achievements as $speedup_type => $amounts) {
            if ($amounts) {
                switch ($speedup_type) {
                    case 'static':
                        self::deductionFirstReleasableOrder($order_info['id'], $order_info['user_id'], (int)$amounts, 'mode_static_release', '');
                        break;
                    case 'direct':
                        foreach ($amounts as $user_id => $amount) {
                            self::deductionFirstReleasableOrder($order_info['id'], $user_id, $amount, 'speedup', 'direct');
                        }
                        break;
                    case 'partner':
                    case 'partner_pingji':
                        foreach ($amounts as $user_id => $amount) {
                            self::releaseAction($user_id, $amount, $order_info['id'], 0, 'speedup', $speedup_type);
                        }
                        break;
                    default:
                        foreach ($amounts as $level_id => $level_amounts) {
                            foreach ($level_amounts as $user_id => $amount) {
                                self::deductionFirstReleasableOrder($order_info['id'], $user_id, $amount, 'speedup', $speedup_type);
                            }
                        }
                        break;
                }
            }
        }
        return true;
    }

    private static function deductionFirstReleasableOrder($from_order_id, $user_id, $total_amount, $type, $speedup_type)
    {

        if ($first_releasable_order = ModeOrders::where('is_delete', 0)->where('type', 4)->where('user_id', $user_id)->where('status', 'payed')->whereNotNull('pay_time')->where('remain_earnings', '>', 0)->order('pay_time', 'asc')->findOrEmpty()->toArray()) {

            if ($current_release_amount = min($total_amount, $first_releasable_order['remain_earnings'])) {

                self::releaseAction($user_id, $current_release_amount, $from_order_id, $first_releasable_order['id'], $type, $speedup_type);

                if (($order_surplus_amount = $total_amount - $current_release_amount) > 0) {

                    return self::deductionFirstReleasableOrder($from_order_id, $user_id, $order_surplus_amount, $type, $speedup_type);

                }
            }

        }
        return true;
    }

    private static function releaseAction($user_id, $amount, $from_order_id, $release_order_id, $type, $speedup_type)
    {
        if ($amount <= 0) {
            return true;
        }

        Db::startTrans();

        try {

            if ($type == 'speedup' && Str::startsWith($speedup_type, 'partner')) {

                $log_content = '['.$from_order_id.']'.implode('-', [
                    data_get(ModeOrdersLog::TYPES, $type, ''),
                    data_get(ModeOrdersLog::SPEEDUP_TYPES, $speedup_type, '')
                ]);

                //获取最多可销毁福利分
                $amount = min($amount, (int)User::where('id', $user_id)->value('welfare_points'));

                ModeHook::createIncome($user_id, $amount, 0, $amount, 'welfare_points', $type, $log_content);

            } else {

                $log_content = ModeHook::orderRelease($release_order_id, $amount, $from_order_id, $type, $speedup_type);

                $balance = ModeHook::computePercentAmount($amount, self::RATE_OF_BALANCE);
                $fee = ModeHook::computePercentAmount($amount, self::RATE_OF_FEE);
                $integral = $amount - $balance - $fee;

                ModeHook::createIncome($user_id, $balance, $integral, $amount, 'invest_balance', $type, $log_content);
            }


            Db::commit();
        } catch (\Exception $exception) {

            Db::rollback();

            Log::error('ModeThreeOrderRelease:'.json_encode(['message' => $exception->getMessage(), 'file' => $exception->getFile(), 'line' => $exception->getLine()], JSON_UNESCAPED_UNICODE));
        }

        return true;
    }

}